// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_JS_REGEXP_INL_H_
#define V8_OBJECTS_JS_REGEXP_INL_H_

#include "src/objects/js-regexp.h"

#include "src/objects-inl.h" // Needed for write barriers
#include "src/objects/smi.h"
#include "src/objects/string.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

    OBJECT_CONSTRUCTORS_IMPL(JSRegExp, JSObject)

    CAST_ACCESSOR(JSRegExp)

    ACCESSORS(JSRegExp, data, Object, kDataOffset)
    ACCESSORS(JSRegExp, flags, Object, kFlagsOffset)
    ACCESSORS(JSRegExp, source, Object, kSourceOffset)
    ACCESSORS(JSRegExp, last_index, Object, kLastIndexOffset)

    JSRegExp::Type JSRegExp::TypeTag() const
    {
        Object data = this->data();
        if (data->IsUndefined())
            return JSRegExp::NOT_COMPILED;
        Smi smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
        return static_cast<JSRegExp::Type>(smi->value());
    }

    int JSRegExp::CaptureCount()
    {
        switch (TypeTag()) {
        case ATOM:
            return 0;
        case IRREGEXP:
            return Smi::ToInt(DataAt(kIrregexpCaptureCountIndex));
        default:
            UNREACHABLE();
        }
    }

    JSRegExp::Flags JSRegExp::GetFlags()
    {
        DCHECK(this->data()->IsFixedArray());
        Object data = this->data();
        Smi smi = Smi::cast(FixedArray::cast(data)->get(kFlagsIndex));
        return Flags(smi->value());
    }

    String JSRegExp::Pattern()
    {
        DCHECK(this->data()->IsFixedArray());
        Object data = this->data();
        String pattern = String::cast(FixedArray::cast(data)->get(kSourceIndex));
        return pattern;
    }

    Object JSRegExp::CaptureNameMap()
    {
        DCHECK(this->data()->IsFixedArray());
        DCHECK_EQ(TypeTag(), IRREGEXP);
        Object value = DataAt(kIrregexpCaptureNameMapIndex);
        DCHECK_NE(value, Smi::FromInt(JSRegExp::kUninitializedValue));
        return value;
    }

    Object JSRegExp::DataAt(int index) const
    {
        DCHECK(TypeTag() != NOT_COMPILED);
        return FixedArray::cast(data())->get(index);
    }

    void JSRegExp::SetDataAt(int index, Object value)
    {
        DCHECK(TypeTag() != NOT_COMPILED);
        DCHECK_GE(index,
            kDataIndex); // Only implementation data can be set this way.
        FixedArray::cast(data())->set(index, value);
    }

    bool JSRegExp::HasCompiledCode() const
    {
        if (TypeTag() != IRREGEXP)
            return false;
#ifdef DEBUG
        DCHECK(DataAt(kIrregexpLatin1CodeIndex)->IsCode() || DataAt(kIrregexpLatin1CodeIndex)->IsByteArray() || DataAt(kIrregexpLatin1CodeIndex) == Smi::FromInt(kUninitializedValue));
        DCHECK(DataAt(kIrregexpUC16CodeIndex)->IsCode() || DataAt(kIrregexpUC16CodeIndex)->IsByteArray() || DataAt(kIrregexpUC16CodeIndex) == Smi::FromInt(kUninitializedValue));
#endif // DEBUG
        Smi uninitialized = Smi::FromInt(kUninitializedValue);
        return (DataAt(kIrregexpLatin1CodeIndex) != uninitialized || DataAt(kIrregexpUC16CodeIndex) != uninitialized);
    }

    void JSRegExp::DiscardCompiledCodeForSerialization()
    {
        DCHECK(HasCompiledCode());
        SetDataAt(kIrregexpLatin1CodeIndex, Smi::FromInt(kUninitializedValue));
        SetDataAt(kIrregexpUC16CodeIndex, Smi::FromInt(kUninitializedValue));
    }

} // namespace internal
} // namespace v8

#include "src/objects/object-macros-undef.h"

#endif // V8_OBJECTS_JS_REGEXP_INL_H_
